package tagcapturer;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.bind.*;
import javax.xml.namespace.QName;
import epcglobal.ale.*;
import epcglobal.ale.soap.*;

public class ALESOAPClient {
    
    static String server_host = "137.189.33.76";
    static String server_port = "8080";
    static String client_host = "localhost";
    static String client_port = "6666";
    
    static String wspath;
    
    static ALEServicePortType aleServicePort = null;
    
    private static ALEServicePortType retrieveALEServicePort() {
        
        if (aleServicePort != null)
            return aleServicePort;
        
        wspath = "http://" + server_host + ":" + server_port + "/ale-ws/aleservice?wsdl";
        
        ALEService service;
        try {
            service = new ALEService(new URL(wspath), new QName(
                    "urn:epcglobal:ale:wsdl:1", "ALEService"));
            aleServicePort = service.getALEServicePort();
            return aleServicePort;
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return null;
        
    }
    
    public static void define(View view) throws Exception {
        // create an ECSpec instance
        ECSpec spec = new ECSpec();
        
        ECLogicalReaders logicalReaders = new ECLogicalReaders();
        
        for (String reader : view.getReaders().split(";")) {
            logicalReaders.getLogicalReader().add(reader);
        }
        
        spec.setLogicalReaders(logicalReaders);
        
        ECBoundarySpec boundarySpec = new ECBoundarySpec();
        ECTime time = new ECTime();
        time.setUnit(ECTimeUnit.MS);
        time.setValue(3000);
        boundarySpec.setDuration(time);
        spec.setBoundarySpec(boundarySpec);
        
        ECReportSpecs reportSpecs = new ECReportSpecs();
        
        ECReportSpec reportSpec = new ECReportSpec();
        reportSpec.setReportName("report");
        
        ECReportSetSpec reportSetSpec = new ECReportSetSpec();
        switch (view.getReportSet()) {
            case View.CURRENT:
                reportSetSpec.setSet(ECReportSetEnum.CURRENT);
                break;
            case View.ADDITIONS:
                reportSetSpec.setSet(ECReportSetEnum.ADDITIONS);
                break;
            case View.DELETIONS:
                reportSetSpec.setSet(ECReportSetEnum.DELETIONS);
                break;
        }
        
        reportSpec.setReportSet(reportSetSpec);
        
        // setup the filterSpec
        ECFilterSpec filterSpec = new ECFilterSpec();
        
        ECIncludePatterns includePatterns = new ECIncludePatterns();
        
        for (String includePattern : view.getIncludeTags().split(";")) {
            includePatterns.getIncludePattern().add(includePattern);
        }
        
        ECExcludePatterns excludePatterns = new ECExcludePatterns();
        
        filterSpec.setIncludePatterns(includePatterns);
        filterSpec.setExcludePatterns(excludePatterns);
        reportSpec.setFilterSpec(filterSpec);
        
        // setup the groupSpec
        ECGroupSpec groupSpec = new ECGroupSpec();
        reportSpec.setGroupSpec(groupSpec);
        
        ECReportOutputSpec reportOutputSpec = new ECReportOutputSpec();
        reportOutputSpec.setIncludeEPC(false);
        reportOutputSpec.setIncludeTag(true);
        reportOutputSpec.setIncludeRawHex(false);
        reportOutputSpec.setIncludeRawDecimal(false);
        reportOutputSpec.setIncludeCount(true);
        reportSpec.setOutput(reportOutputSpec);
        
        reportSpec.setReportIfEmpty(false);
        reportSpec.setReportOnlyOnChange(false);
        
        reportSpecs.getReportSpec().add(reportSpec);
        spec.setReportSpecs(reportSpecs);
        
        spec.setIncludeSpecInReports(false);
        
        runDefine(spec, view.getTitle());
    }
    
    public static void undefine(String specName) throws Exception {
        runUndefine(specName);
    }
    
    public static void subscribe(String specName) throws Exception {
        runSubscribe(specName,"tcp://" +  client_host + ":" + client_port + "/" + specName);
    }
    
    public static void unsubscribe(String specName) throws Exception {
        runUnsubscribe(specName,"tcp://" +  client_host + ":" + client_port + "/" + specName);
    }
    
    private static void runUnsubscribe(String specName, String notificationUri)
    throws ImplementationExceptionResponse,
            InvalidURIExceptionResponse, NoSuchNameExceptionResponse,
            NoSuchSubscriberExceptionResponse, SecurityExceptionResponse {
        ALEServicePortType port = retrieveALEServicePort();
        Unsubscribe parms = new Unsubscribe();
        parms.setSpecName(specName);
        parms.setNotificationURI(notificationUri);
        port.unsubscribe(parms);
        
    }
    
    private static void runSubscribe(String specName, String notificationUri)
    throws DuplicateSubscriptionExceptionResponse,
            ImplementationExceptionResponse, InvalidURIExceptionResponse,
            NoSuchNameExceptionResponse, SecurityExceptionResponse {
        ALEServicePortType port = retrieveALEServicePort();
        Subscribe parms = new Subscribe();
        parms.setSpecName(specName);
        parms.setNotificationURI(notificationUri);
        port.subscribe(parms);
    }
    
    private static ArrayOfString runGetECSpecNames()
    throws ImplementationExceptionResponse, SecurityExceptionResponse {
        ALEServicePortType port = retrieveALEServicePort();
        return port.getECSpecNames(new EmptyParms());
    }
    
    private static ECSpec runGetECSpec(String specName)
    throws ImplementationExceptionResponse, SecurityExceptionResponse {
        ALEServicePortType port = retrieveALEServicePort();
        GetECSpec parms = new GetECSpec();
        parms.setSpecName(specName);
        return port.getECSpec(parms);
    }
    
    private static void runUndefine(String sampleSpecName)
    throws ImplementationExceptionResponse,
            NoSuchNameExceptionResponse, SecurityExceptionResponse {
        ALEServicePortType port = retrieveALEServicePort();
        Undefine parms = new Undefine();
        parms.setSpecName(sampleSpecName);
        port.undefine(parms);
    }
    
    private static void runDefine(ECSpec sampleECSpec, String sampleSpecName)
    throws DuplicateNameExceptionResponse,
            ECSpecValidationExceptionResponse, ImplementationExceptionResponse,
            SecurityExceptionResponse {
        ALEServicePortType port = retrieveALEServicePort();
        Define parms = new Define();
        parms.setSpec(sampleECSpec);
        parms.setSpecName(sampleSpecName);
        port.define(parms);
    }
    
    private static ArrayOfString runGetSubscribers(String sampleSpecName) throws ImplementationExceptionResponse, NoSuchNameExceptionResponse, SecurityExceptionResponse {
        ALEServicePortType port = retrieveALEServicePort();
        GetSubscribers parms = new GetSubscribers();
        parms.setSpecName(sampleSpecName);
        return port.getSubscribers(parms);
    }
    
    private static String runGetVendorVersion() throws ImplementationExceptionResponse{
        ALEServicePortType port = retrieveALEServicePort();
        return port.getVendorVersion(new EmptyParms());
        
    }
    
    private static String runGetStandardVersion() throws ImplementationExceptionResponse{
        ALEServicePortType port = retrieveALEServicePort();
        return port.getStandardVersion(new EmptyParms());
    }
    
    private static ECReports runPoll(String sampleSpecName) throws ImplementationExceptionResponse, NoSuchNameExceptionResponse, SecurityExceptionResponse {
        ALEServicePortType port = retrieveALEServicePort();
        Poll parms = new Poll();
        parms.setSpecName(sampleSpecName);
        return port.poll(parms);
    }
    
    private static ECReports runImmediate(ECSpec sampleECSpec) throws ECSpecValidationExceptionResponse, ImplementationExceptionResponse, SecurityExceptionResponse {
        ALEServicePortType port = retrieveALEServicePort();
        Immediate parms = new Immediate();
        parms.setSpec(sampleECSpec);
        return port.immediate(parms);
    }
    
    
    private static ECSpec getECSpecFromFile(String filename) {
        try {
            JAXBContext jc;
            jc = JAXBContext.newInstance("epcglobal.ale");
            Unmarshaller u = jc.createUnmarshaller();
            JAXBElement element = (JAXBElement) u
                    .unmarshal(new FileInputStream(filename));
            ECSpec retval = (ECSpec) element.getValue();
            return retval;
        } catch (JAXBException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}
